import { FlowComponent, createContext, createEffect, on, useContext } from 'solid-js'
import { Agent, Skill, Skills } from './skill'
import { Store, createStore, produce } from 'solid-js/store'
import { load, save } from './storage'

export type Config = {
  skill: Skills
  agent: Agent
  autoRematch: number
  saveStat: boolean
}

type State = Config & {
  my: number
  their: number
  result: -1 | 0 | 1
  record: [Skill, Skill][]
  update: unknown // 局面的变化
  stat: { win: number, lose: number }
  userCfg: Partial<Config>
}

export type Game = {
  store: Store<State>
  rematch: () => void
  round: (skill1: Skill, skill2: Skill) => void
  setCfg: <K extends keyof Config>(k: K, cfg: Config[K]) => void
  clearData: () => void
  clearStat: () => void
}

const GameContext = createContext<Game>()

export const useGame = () => useContext(GameContext)!

type StateProvider = FlowComponent<{
  defaultConfig: Config
}>
export const GameProvider: StateProvider = prop => {
  const { stat, ...userCfg } = load()
  const [store, setStore] = createStore<State>({
    ...prop.defaultConfig,
    ...userCfg,
    userCfg,
    stat: stat ?? newStat(),
    ...newGame(),
    get update() { return this.record.length }
  })

  createEffect(on(() => store.skill, () => {
    game.rematch()
  }, { defer: true }))

  createEffect(on(() => store.result, res => {
    if (res == 0) return
    setStore('stat', res == 1 ? 'win' : 'lose', x => x + 1)
  }, { defer: true }))

  createEffect(on(() => ({
    ...store.userCfg,
    stat: store.saveStat ? { ...store.stat } : undefined
  }), save, { defer: true }))

  const game: Game = {
    store,
    setCfg(k, cfg) {
      setStore({ [k]: cfg })
      setStore('userCfg', { [k]: cfg })
    },
    clearData() {
      setStore(prop.defaultConfig)
      setStore({ userCfg: {} }) // 避免合并
      game.clearStat()
    },
    clearStat() {
      setStore('stat', newStat)
    },
    rematch() {
      setStore(newGame)
    },
    round(skill1, skill2) {
      setStore(({ my, their, skill }) => ({
        result: skill[skill1].versus[skill2],
        my: my - skill[skill1].cost,
        their: their - skill[skill2].cost,
      }))
      setStore('record', produce(record =>
        record.push([skill1, skill2])))
    },
  }

  return <GameContext.Provider value={game}>
    {prop.children}
  </GameContext.Provider>
}

const newGame = () => ({
  my: 0,
  their: 0,
  result: 0,
  record: [],
} satisfies Partial<State>)

const newStat = () => ({ win: 0, lose: 0 })
